﻿/**
 * CJUtils
 *
 * @author		Allen Chou
 * @version		1.0.1 (last update: Jan 24 2008)
 * @link        http://cjcat.blogspot.com
 * @link		http://cjcat2266.deviantart.com
 */

package idv.cjcat{
	import flash.events.*;
	import flash.errors.*;
	import flash.utils.*;

	/**
	 *  The <code>CJUtils</code> contains some common utility operations on Arrays.
	 */
	public class CJUtils {
		
		//delay call utility
		//------------------------------------------------------------------------------------------------
		private static var delayCallQueue:Vector.<DelayCallData>;
		/**
		 * Delays a function call for a specified time.
		 * @param	func    The function to be called.
		 * @param	delay   The time of delay in seconds.
		 * @param	params  The parameters to be passed when the function is called.
		 */
		public static function delayCall(func:Function, delay:Number, params:Array = null):void {
			delay = CJMath.clamp(delay, 0, Number.MAX_VALUE);
			if (delayCallQueue === null) delayCallQueue = new Vector.<DelayCallData>();
			if (delayCallQueue.length == 0) CJGlobal.sprite.addEventListener(Event.ENTER_FRAME, delayLoop);
			delayCallQueue.push(new DelayCallData(func, getTimer() + int(delay * 1000), params));
		}
		private static function delayLoop(e:Event):void {
			delayCallQueue = delayCallQueue.filter(delayDataFilter);
			if (delayCallQueue.length == 0) CJGlobal.sprite.removeEventListener(Event.ENTER_FRAME, delayLoop);
		}
		private static function delayDataFilter(data:DelayCallData, index:int, vec:Vector.<DelayCallData>):Boolean {
			if (getTimer() >= data.death) {
				data.func.apply(null, data.params);
				return false;
			}
			return true;
		}
		//------------------------------------------------------------------------------------------------
		//end of delay call utility
		
		
		/**
		 * Determines if the value of a variable is primitive-type.
		 * @param	value  The value of the variable to be examined.
		 * @return  If the value of the variable is primitive-type.
		 */
		public static function isPrimitive(value:*):Boolean {
			if (value is Boolean) return true;
			if (value is Number) return true;
			if (value is int) return true;
			if (value is uint) return true;
			if (value is String) return true;
			return false;
		}
		
		/**
		 * Adds a unique element to an Array
		 * @param	array    The array.
		 * @param	element  The element to be added.
		 * @return The element added.
		 */
		public static function addUniqueElement(array:Array, element:Object):Object {
			for (var i:int = 0; i < array.length; i++) {
				if (array[i] === element) {
					array.splice(i, 1);
					break;
				}
			}
			array.push(element);
			return element;
		}
		
		/**
		 * Removes an element from an Array.
		 * @param	array
		 * @param	element
		 */
		public static function removeElement(array:Array, element:Object):void {
			for (var i:int = array.length - 1; i >= 0; i--) {
				if (array[i] === element) array.splice(i, 1);
			}
		}
		
		/**
		 * Removes a unique element from an Array.
		 * @param	array
		 * @param	element
		 * @return The removed element.
		 */
		public static function removeUniqueElement(array:Array, element:Object):Object {
			for each (var obj:Object in array) {
				if (obj === element) {
					array.splice(array.indexOf(obj), 1);
					return obj;
				}
			}
			return null;
		}
		
		/**
		 * Combines two Arrays as two sets; that is, unions two Arrays.
		 * @param	array1  The first Array.
		 * @param	array2  The second Array.
		 * @return The union of the two Arrays.
		 */
		public static function mergeArrays(array1:Array, array2:Array):Array {
			var temp:Array = new Array();
			for (var i:int = 0; i < array1.length; i++) {
				temp.push(array1[i]);
			}
			for (var j:int = 0; j < array2.length; j++) {
				CJUtils.addUniqueElement(temp, array2[j]);
			}
			return temp;
		}
		
		/**
		 * Checks if two objects are equal or refers to the same object.
		 * @param	obj1  The first object.
		 * @param	obj2  The second object.
		 * @return Whether the two objects are equal or refers to the same object.
		 */
		public static function equal(obj1:Object, obj2:Object):Boolean {
			return Boolean(obj1 === obj2);
		}
		
	}
}

internal class DelayCallData {
	internal var func:Function;
	internal var death:int = 0;
	internal var params:Array;
	public function DelayCallData(func:Function, death:int, params:Array):void {
		this.func = func;
		this.death = death;
		this.params = params;
	}
}